package com.dddframework.security.domain.auth.component;

import com.dddframework.core.contract.R;
import com.dddframework.core.contract.exception.ServiceException;
import com.dddframework.kit.lang.StrKit;
import com.dddframework.security.infras.exception.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.web.HttpRequestMethodNotSupportedException;

/**
 * 异常处理, 重写oauth 默认实现
 *
 * @author zhouzx
 */
@Slf4j
public class BaseWebResponseExceptionTranslator implements WebResponseExceptionTranslator {
    private static final String INVALID_TOKEN_ERROR_DESCRIPTION = "Token was not recognised";
    private static final String INVALID_AUTHORIZATION_CODE = "Invalid authorization code";
    private static final String INVALID_USER = "无效用户";
    private static final String BAD_CREDENTIALS = "Bad credentials";

    private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();

    @Override
    public ResponseEntity translate(Exception e) {
        // Try to extract a SpringSecurityException from the stacktrace
        Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
        Exception ase = (ServiceException) throwableAnalyzer.getFirstThrowableOfType(ServiceException.class, causeChain);
        if (ase != null) {
            ServiceException exception = (ServiceException) ase;
            if (StrKit.isNotBlank(exception.getMessage()) && exception.getCode() != null) {
                return ResponseEntity.ok().body(R.fail(exception.getCode(), exception.getMessage()));
            } else if (StrKit.isNotBlank(exception.getMessage())) {
                return ResponseEntity.ok().body(R.fail(exception.getMessage()));
            } else {
                return ResponseEntity.ok().body(R.fail("服务器内部错误，请联系管理员！"));
            }
        }
        ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e));
        }
        ase = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new ForbiddenException(ase.getMessage(), ase));
        }
        ase = (InvalidGrantException) throwableAnalyzer.getFirstThrowableOfType(InvalidGrantException.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new InvalidException(ase.getMessage(), ase));
        }
        ase = (HttpRequestMethodNotSupportedException) throwableAnalyzer.getFirstThrowableOfType(HttpRequestMethodNotSupportedException.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception(new MethodNotAllowedException(ase.getMessage(), ase));
        }
        ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain);
        if (ase != null) {
            return handleOAuth2Exception((OAuth2Exception) ase);
        }
        return handleOAuth2Exception(new ServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), e));

    }

    private ResponseEntity handleOAuth2Exception(OAuth2Exception e) {
        int status = e.getHttpErrorCode();
        //HttpHeaders headers = new HttpHeaders();
        //headers.set(HttpHeaders.CACHE_CONTROL, "no-store");
        //headers.set(HttpHeaders.PRAGMA, "no-cache");
        //if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) {
        //	headers.set(HttpHeaders.WWW_AUTHENTICATE, String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary()));
        //}
        // 客户端异常直接返回客户端,不然无法解析
        //if (e instanceof ClientAuthenticationException) {
        //	return new ResponseEntity<>(e, headers,
        //		HttpStatus.valueOf(status));
        //}
        if (e.getMessage().startsWith(INVALID_AUTHORIZATION_CODE)) {
            return ResponseEntity.ok().body(R.fail(status, e.getMessage()));
        } else if (INVALID_USER.equals(e.getMessage())) {
            return ResponseEntity.ok().body(R.fail(status, e.getMessage()));
        } else if (BAD_CREDENTIALS.equals(e.getMessage())) {
            return ResponseEntity.ok().body(R.fail(status, "密码错误"));
        } else if (INVALID_TOKEN_ERROR_DESCRIPTION.equals(e.getMessage())) {
            return ResponseEntity.ok().body(R.fail(status, "token无效"));
        } else {
            return ResponseEntity.ok().body(R.fail(e.getOAuth2ErrorCode(), e.getMessage()));
        }
    }
}